package AdminDB;

import Other.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;


public class UsersGui {

	//GUI objects
    private Shell shell;
    private Table table;
    private Users users;
    private Font font;
    private Button addUserButton;
    private Button removeUserButton;
    private Button nextButton;
    private Button prevButton;
    public static int usersToDisplay;

    public UsersGui(Shell shell) {
        FormLayout layout = new FormLayout();
        this.shell = shell;
        this.font = new Font(shell.getDisplay(), "Consolas", 13, SWT.NORMAL);
        shell.setBounds(5, 5, 763, 500);
        shell.setText("Users List");
        shell.setLayout(layout);
        initTable();
        initUsers();
        loadUsers();
        addTableListener();
        createButtons();
        addButtonListeners();        
    }

    private void initUsers() {
        this.users = new UsersConcrete(usersToDisplay);
    }

    /** Creates all the GUI object buttons
     * 
     */
    private void createButtons() {
       this.prevButton = new Button(shell, SWT.PUSH) ;
       prevButton.setText("Previous");
       prevButton.setFont(font);
       FormData prevButtonFD = locateButton(130, 50, 71,  69, 1, 15);
       prevButton.setLayoutData(prevButtonFD);
       prevButton.setToolTipText("Click to view the previous batch of users");

       this.nextButton = new Button(shell, SWT.PUSH) ;
       nextButton.setText("Next");
       nextButton.setFont(font);
       FormData nextButtonFD = locateButton(130, 50, 71,  69, 69, 80);
       nextButton.setLayoutData(nextButtonFD);
       nextButton.setToolTipText("Click to view the next batch of users");

       this.addUserButton = new Button(shell, SWT.PUSH) ;
       addUserButton.setText("Add User");
       addUserButton.setFont(font);
       FormData addUserButtonFD = locateButton(130, 50, 71,  69, 39, 80);
       addUserButton.setLayoutData(addUserButtonFD);
       addUserButton.setToolTipText("Add a new User");

       this.removeUserButton =new Button(shell, SWT.PUSH) ;
       removeUserButton.setText("Remove User");
       removeUserButton.setFont(font);
       FormData removeUserButtonFD = locateButton(130, 50, 71,  69, 29, 25);
       removeUserButton.setLayoutData(removeUserButtonFD);
       removeUserButton.setToolTipText("Deletes a User");
    }

    /** Adds listeners to created buttons
     * 
     */
    private void addButtonListeners() {
    	// done
        prevButton.addSelectionListener(new SelectionListener() {

            public void widgetSelected(SelectionEvent e) {
            	shell.getDisplay().asyncExec(new Runnable(){
            		public void run(){
            			prevButtonLogic();
            		}
            	});
                
            }

            public void widgetDefaultSelected(SelectionEvent e) {
            }
        });

        // done
        nextButton.addSelectionListener( new SelectionListener() {

            public void widgetSelected(SelectionEvent e) {
            	shell.getDisplay().asyncExec(new Runnable(){
            		public void run(){
            			 nextButtonLogic();
            		}
            	});
               
            }

            public void widgetDefaultSelected(SelectionEvent e) {
            }
        });

        // done
        removeUserButton.addSelectionListener(new SelectionListener() {
            public void widgetSelected(SelectionEvent e) {
            	shell.getDisplay().asyncExec(new Runnable(){
            		public void run(){
            			removeUserButtonLogic();
            		}
            	});
            }

            public void widgetDefaultSelected(SelectionEvent e) {
            }
        });

        // done
        addUserButton.addSelectionListener(new SelectionListener() {
            public void widgetSelected(SelectionEvent e) {
                new DialogEditUser();
            }
            public void widgetDefaultSelected(SelectionEvent e) {
            }
        });
    }

    private void saveChangesToTable(final String name, final String pw, final String desc,
        final String login, final Integer nWin, final Integer nLose, final int index) {
    	
    	final Display display = Display.getDefault();
    	final Shell waitShell = new Shell(display, SWT.NO_REDRAW_RESIZE);
    	new WaitMessage(waitShell, "Waiting for Database...");
    	waitShell.open();
    	waitShell.setLocation(250, 250);
    	
    	Thread execDB = new Thread(new Runnable(){
    		public void run(){
    			display.asyncExec(new Runnable(){
    				@Override
    				public void run() {
    					users.updateUser(new UserConcrete(name, pw, desc, login, nWin, nLose), index);
    					waitShell.close();
    					loadUsers();   			        
    				}   	    		
    	    	});
    		}
    	});
        execDB.start();
    	
    	while(!waitShell.isDisposed()){
    		if(!waitShell.getDisplay().readAndDispatch()){
         		waitShell.getDisplay().sleep();
         	}
        }
    }

    /** load next page from database
     * 
     */
    private void nextButtonLogic() {
    	final Display display = Display.getDefault();
    	final Shell waitShell = new Shell(display, SWT.NO_REDRAW_RESIZE);
    	new WaitMessage(waitShell, "Waiting for Database...");
    	waitShell.open();
    	waitShell.setLocation(250, 250);
    	
    	Thread execDB = new Thread(new Runnable(){
    		public void run(){
    			display.asyncExec(new Runnable(){ 	    		
    				@Override
    				public void run() {
    					users.toNextPage();
    					waitShell.close();
    			        loadUsers();
    				}   	  
    	    	});
    		}
    	});
    	execDB.start();
    	
    	while(!waitShell.isDisposed()){
    		if(!waitShell.getDisplay().readAndDispatch()){
    			waitShell.getDisplay().sleep();
         	}
        }    
    }

    /** load previous page from database
     * 
     */
    private void prevButtonLogic() {
    	final Display display = Display.getDefault();
    	final Shell waitShell = new Shell(display, SWT.NO_REDRAW_RESIZE);
    	new WaitMessage(waitShell, "Waiting for Database...");
    	waitShell.open();
    	waitShell.setLocation(250, 250);
    	
    	Thread execDB = new Thread(new Runnable(){
    		public void run(){
    			display.asyncExec(new Runnable(){	    		
    				@Override
    				public void run() {
    					users.toPreviousPage();
    					waitShell.close();
    			        loadUsers();
    				}  	  
    	    	});    	    	
    		}
    	});
    	execDB.start();
    	
    	while(!waitShell.isDisposed()){
    		if(!waitShell.getDisplay().readAndDispatch()){
    			waitShell.getDisplay().sleep();
         	}
        }    
    }

    /** Loads the users from the database
     * 
     */
    private void loadUsers() {
        table.removeAll();
        for (int i = 0; i < users.getNumOfUsers(); ++i) {
            User user = users.getUser(i);
            TableItem item = new TableItem(table, SWT.NONE, i);
            item.setText(0, user.getName());
            item.setText(1, user.getPassword());
            item.setText(2, user.getDescription());
            item.setText(3, user.getLastLogin());
            item.setText(4, user.getNumOfWin().toString());
            item.setText(5, user.getNumOfLose().toString());
        }
    }

    // remove user from database
    private void removeUserButtonLogic() {
        final int index = table.getSelectionIndex();
        if(index >= 0) {
            String name = table.getItem(index).getText(0);
            MessageBox mb = new MessageBox(shell, SWT.ICON_QUESTION | SWT.OK | SWT.CANCEL);
            mb.setMessage("Are you sure?");
            mb.setText("Deleting User '" + name + "'");
            int userSelect = mb.open();
            if (SWT.OK == userSelect) {
            	
            	final Display display = Display.getDefault();
            	final Shell waitShell = new Shell(display, SWT.NO_REDRAW_RESIZE);
            	new WaitMessage(waitShell, "Waiting for Database...");
            	waitShell.open();
            	waitShell.setLocation(250, 250);
            	
            	Thread execDB = new Thread(new Runnable(){
            		public void run(){
            			display.asyncExec(new Runnable(){
            				public void run(){
            					users.removeUser(index);
        						waitShell.close();
        		                loadUsers();
            				}
            			});          			
            		}
            	});
            	execDB.start();
            	
            	while(!waitShell.isDisposed()){
            		if(!waitShell.getDisplay().readAndDispatch()){
            			waitShell.getDisplay().sleep();
                 	}
                 }    
            }
        }
    }

    /** Adds a new user and saves it to the DB
     * name, pw and desc fields must not be empty
     */
    private void addUserButtonLogic(final String name, final String pw, final String desc,
        final String login, final Integer nWin, final Integer nLose) {
    	
    	final Display display = Display.getDefault();
    	final Shell waitShell = new Shell(display, SWT.NO_REDRAW_RESIZE);
    	new WaitMessage(waitShell, "Waiting for Database...");
    	waitShell.open();
    	waitShell.setLocation(250, 250);
    	
    	Thread execDB = new Thread(new Runnable(){
    		public void run(){
    			display.asyncExec(new Runnable(){	        	
    				@Override
    				public void run() {
    					users.addUser(new UserConcrete(name, pw, desc, login, nWin, nLose));
    					waitShell.close();
    					loadUsers();
    				}  	        	
    	        });  
    		}
    	});
    	execDB.start();
    	
        while(!waitShell.isDisposed()){
        	if(!waitShell.getDisplay().readAndDispatch()){
        		waitShell.getDisplay().sleep();
        	}
        }
    }

    /** Adds a listener to the table
     *  Double-clicking will result in
     *  Viewing and editing a user
     */
    private void addTableListener() {
        table.addSelectionListener(new SelectionListener() {

            public void widgetSelected(SelectionEvent e) {
            }

            public void widgetDefaultSelected(SelectionEvent e) {
                if (table.getSelection().length > 0) {
                    TableItem item = table.getSelection()[0];
                    String name = item.getText(0);
                    String pw = item.getText(1);
                    String descript = item.getText(2);
                    String login = item.getText(3);
                    String wins = item.getText(4);
                    String loses = item.getText(5);
                    new DialogEditUser(name, pw, descript, login, wins, loses,
                            table.getSelectionIndex());
                }

            }
        });
    }

    /** Popup dialog used for editing and viewing a user
     * 
     */
    private class DialogEditUser {

    	//GUI objects
        private Text nameInput, pwInput, descriptInput,
                loginInput, winInput, loseInput;
        private Label name, pw, descript, login, win, lose;
        private Button button;
        
        //GUI logic
        private boolean isNewCard;

        /** Displays a messagebox with error errString
         */
        private void showError(Shell shell, String errString) {
            MessageBox mb = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
            mb.setMessage(errString);
            mb.setText("Unable to save changes");
            mb.open();
        }

        /** Checks if String contains a non-whitespace input
         * 
         */
        private boolean containsRealTextInput(String in) {
            for (int i = 0; i < in.length(); ++i) {
                char c = in.charAt(i);
                if ((' ' == c) || ('\n' == c) || ('\t' == c)) {
                    continue;
                } else {
                    return true;
                }
            }
            return false;
        }

        /** Checks if char is a number
         * 
         */
        private boolean isNum(char c) {
            if (('0' <= c) && ('9' >= c)) {
                return true;
            } else {
                return false;
            }
        }

        /** Checks if a string is a positive integer
         */
        private boolean isStringANumber(String num) {
            for (int i = 0; i < num.length(); ++i) {
                if (!isNum(num.charAt(i))) {
                    return false;
                }
            }
            return true;
        }

        /** Popups a new dialog which receives the following:
         *  username, password, description, wins and loses
         *  username, password and description must not be empty
         *  wins and loses must be a positive integer
         */
        private void initDialogAddCard(Shell shell, Display display) {
            shell.setLayout(new GridLayout(2, false));
            name = new Label(shell, SWT.NULL);
            name.setText("Username:");
            nameInput = new Text(shell, SWT.SINGLE | SWT.BORDER);
            nameInput.setTextLimit(30);
            nameInput.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

            pw = new Label(shell, SWT.NULL);
            pw.setText("Password:");
            pwInput = new Text(shell, SWT.SINGLE | SWT.BORDER);
            pwInput.setTextLimit(20);
            pwInput.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

            descript = new Label(shell, SWT.NULL);
            descript.setText("Description:");
            descriptInput = new Text(shell, SWT.MULTI | SWT.BORDER);
            descriptInput.setTextLimit(1024);
            descriptInput.setLayoutData(new GridData(GridData.FILL_BOTH));

            login = new Label(shell, SWT.NULL);
            login.setText("Last Login:");
            loginInput = new Text(shell, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY);
            loginInput.setTextLimit(12);
            loginInput.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

            win = new Label(shell, SWT.NULL);
            win.setText("Wins:");
            winInput = new Text(shell, SWT.SINGLE | SWT.BORDER);
            winInput.setTextLimit(5);
            winInput.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

            lose = new Label(shell, SWT.NULL);
            lose.setText("Lost:");
            loseInput = new Text(shell, SWT.SINGLE | SWT.BORDER);
            loseInput.setTextLimit(5);
            loseInput.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

            this.button = new Button(shell, SWT.PUSH);
            button.setText("Submit");
        }

        /** Adds a listener to the submit button
         *  if selected, checks if input is legal
         *  if it is: add the user
         *  else: show an error message box
         */
        private void addButtonListener(final Shell shell, final int index) {
            button.addSelectionListener(new SelectionListener() {

                public void widgetSelected(SelectionEvent e) {
                    final String username = nameInput.getText();
                    final String password = pwInput.getText();
                    final String description = descriptInput.getText();
                    final String lastLogin = loginInput.getText();
                    final String nWin = winInput.getText();
                    final String nLose = loseInput.getText();

                    if (!username.isEmpty() && !password.isEmpty() && !description.isEmpty()) {
                        boolean chkName = containsRealTextInput(username);
                        boolean chkDesc = containsRealTextInput(description);
                        boolean chkWin, chkLose;
                        if (!nWin.isEmpty()) {
                            chkWin = isStringANumber(nWin);
                        } else {
                            chkWin = true;
                        }
                        if (!nLose.isEmpty()) {
                            chkLose = isStringANumber(nLose);
                        } else {
                            chkLose = true;
                        }
                        if (chkName && chkWin && chkLose && chkDesc) {
                            final Integer winInt, loseInt;
                            if(nWin.isEmpty()) winInt=0;
                            else winInt = Integer.parseInt(nWin);
                            if(nLose.isEmpty()) loseInt=0;
                            else loseInt = Integer.parseInt(nLose);  
                            
                            shell.getDisplay().asyncExec(new Runnable(){
                            	public void run(){
                            		 if (isNewCard) {
                                         addUserButtonLogic(username, password, description, lastLogin, winInt, loseInt);
                                     } else {
                                         saveChangesToTable(username, password, description, lastLogin, winInt, loseInt, index);
                                     }
                                     shell.close();
                            	}
                            });
                           
                            
                        } else if (!chkName) {
                            showError(shell, "Name is only whitespace!");
                        } else if (!chkWin){
                            showError(shell, "Wins input is not an integer");
                        }
                        else if (!chkDesc) {
                        	showError(shell, "Description is only whitespace!");
                        }
                        else showError(shell, "Loses input is not an integer");

                    } else if (username.isEmpty()) {
                        showError(shell, "Username input is empty!");
                    }
                    else if(description.isEmpty()) {
                    	showError(shell, "Description input is empty!");
                    }                    
                    else {
                        showError(shell, "Password input is empty!");
                    }
                }

                public void widgetDefaultSelected(SelectionEvent e) {
                }
            });
        }
        
        /** Constructor for a new user
         * 
         */
        private DialogEditUser() {
            Display display = shell.getDisplay();
            final Shell shell = new Shell(display);
            shell.setText("Add new User");
            initDialogAddCard(shell, display);
            nameInput.setText("");
            pwInput.setText("");
            descriptInput.setText("");
            loginInput.setText("");
            winInput.setText("");
            loseInput.setText("");
            this.isNewCard=true;
            button.setToolTipText("Click to add new user");
            addButtonListener(shell, -1);
            shell.pack();
            shell.open();
            while (!shell.isDisposed()) {
                if (!display.readAndDispatch()) {
                    display.sleep();
                }
            }
        }        

        /** Constructor for editing an existing user
         */
        private DialogEditUser(String name, String password, String description,
            String lastLogin, String nWins, String nLoses, int index) {
            Display display = shell.getDisplay();
            final Shell shell = new Shell(display);
            shell.setText("View and Edit User");

            initDialogAddCard(shell, display);
            nameInput.setText(name);
            pwInput.setText(password);
            descriptInput.setText(description);
            loginInput.setText(lastLogin);
            winInput.setText(nWins);
            loseInput.setText(nLoses);
            this.isNewCard = false;
            button.setToolTipText("Click to save changes");
            addButtonListener(shell, index);
            shell.pack();
            shell.open();
            while (!shell.isDisposed()) {
                if (!display.readAndDispatch()) {
                    display.sleep();
                }
            }
        }
    }

    /** Returns a formdata for an GUI object
     */
    private FormData locateButton(int width, int height, int top1, int top2,
            int left1, int left2) {
        FormData result = new FormData(width, height);
        result.top = new FormAttachment(top1, top2);
        result.left = new FormAttachment(left1, left2);
        return result;
    }

    /** Initializes the table object
     * 
     */
    private void initTable() {
        this.table = new Table(shell, SWT.SINGLE | SWT.BORDER | SWT.VIRTUAL | SWT.FULL_SELECTION);
        table.setLinesVisible(true);
        table.setHeaderVisible(true);
        table.setFont(font);
        FormData tableFD = locateButton(721, 365, 1, 1, 1, 1);
        table.setLayoutData(tableFD);
        String[] titles = {"User", "Password", "Description", "Last login", "Wins", "Loses"};
        for (int i = 0; i < titles.length; i++) {
            TableColumn column = new TableColumn(table, SWT.NONE);
            column.setText(titles[i]);
        }
        for (int i = 0; i < titles.length; i++) {
            table.getColumn(i).pack();
        }
        table.getColumn(0).setWidth(150);
        table.getColumn(1).setWidth(150);
        table.getColumn(2).setWidth(200);
        table.setToolTipText("Double-click to view and edit a user");
    }
    
    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display, SWT.MENU);
        new UsersGui(shell);
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    }

}